# -*- coding: GBK -*-

import unittest
import sys
import cPickle
import time


sys.path.append('..')
sys.path.append('../common')
sys.path.append('../network')
sys.path.append('../common_server')

import conf
from events import MsgCSLogin, MsgCSMoveto
from dispatcher import Service, Dispatcher
from netStream import NetStream, RpcProxy
from simpleHost import SimpleHost
from timer import TimerManager

class TestService(Service):
    def __init__(self, sid = 0):
        super(TestService, self).__init__(sid)
        commands = {
            10 : self.f,
            20 : self.f,
        }
        self.registers(commands)

    def f(self, msg, owner):
        return owner

class MsgService(object):
    pass


def EXPOSED(func):
    func.__exposed__ = True
    return func

class GameEntity(object):
    EXPOSED_FUNC = {}
    def __init__(self, netstream):
        self.netstream = netstream
        self.caller = RpcProxy(self, netstream)
        self.stat = 0

    def destroy(self):
        self.caller = None
        self.netstream = None

    # SERVER CODE
    @EXPOSED
    def hello_world_from_client(self, stat, msg):
        print 'server recv msg from client:', stat, msg
        self.stat = stat + 1
        self.caller.recv_msg_from_server(self.stat, msg)

    @EXPOSED
    def exit(self):
        print 'client exit, set stat to -1:'
        self.stat = -1
    ###

class ServerTest(unittest.TestCase):
    def setUp(self):
        self._head1 = MsgCSLogin('test', 0)
        self._head2 = MsgCSMoveto(3, 5)

        self._dispatcher = Dispatcher()
        self._dispatcher.register(100, TestService())

        self.count = 0

    def tearDown(self):
        self._head1 = None
        self._head2 = None

        self._dispatcher = None

        self.count = 0

    def addCount(self):
        self.count += 1

    def test_Parser(self):
        # test header

        data = self._head1.marshal()
        head = MsgCSLogin().unmarshal(data)
        self.assertEqual(self._head1.name, head.name)
        self.assertEqual(self._head1.icon, head.icon)

        data = self._head2.marshal()
        head = MsgCSMoveto().unmarshal(data)
        self.assertEqual(self._head2.x, head.x)
        self.assertEqual(self._head2.y, head.y)

        # test dispatcher
        msg = MsgService()
        msg.sid = 100
        msg.cid = 10
        self.assertEqual(self._dispatcher.dispatch(msg, 'client1'), 'client1')
        msg.cid = 20
        self.assertEqual(self._dispatcher.dispatch(msg, 'client2'), 'client2')

        # test network
        host = SimpleHost()
        host.startup(2000)
        sock = NetStream()
        last = time.time()
        sock.connect('127.0.0.1', 2000)

        stat = 0
        last = time.time()
        sock.nodelay(1)

        server_entity = None

        # test timer
        TimerManager.addRepeatTimer(0.15, self.addCount)
        last = time.time()

        while 1:
            time.sleep(0.1)

            ### Timer
            TimerManager.scheduler()

            # if time.time() - last > 1.0:
            #     break
            print 'main loop %d' % self.count

            ### SERVER SECTION
            host.process()
            event, wparam, data = host.read()
            if event < 0:
                continue

            if event == conf.NET_CONNECTION_NEW:
                code, client_netstream = host.getClient(wparam)
                self.assertGreaterEqual(code, 0)
                server_entity = GameEntity(client_netstream)

            elif event == conf.NET_CONNECTION_DATA:
                server_entity.caller.parse_rpc(data)

                if server_entity.stat == -1:
                    server_entity.destroy()
                    host.closeClient(wparam)
                    host.shutdown()
                    break
            ###

        self.assertEqual(self.count, 6)
        return

if __name__ == '__main__':
    unittest.main()
